{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a9f4021c",
   "metadata": {},
   "source": [
    "# LangSmith 데이터셋 생성\n",
    "\n",
    "자체 RAG 평가용 데이터셋을 구축하는 방법에 대해 알아보겠습니다.\n",
    "\n",
    "먼저, 데이터셋 구축을 위해서는 크게 3가지 과정에 대한 이해가 필요합니다.\n",
    "\n",
    "Case: Retrieval 이 Question 에 Relevant 한지 평가\n",
    "\n",
    "> Question - Retrieval\n",
    "\n",
    "![](./assets/eval-03.png)\n",
    "\n",
    "Case: Answer 이 Question 에 Relevant 한지 평가\n",
    "\n",
    "> Question - Answer   \n",
    "\n",
    "![](./assets/eval-04.png)\n",
    "\n",
    "Case: Answer 가 Retrieval 된 문서 안에서 답변하였는지 (Hallucination Check)\n",
    "\n",
    "> Retrieval - Answer\n",
    "\n",
    "![](./assets/eval-05.png)\n",
    "\n",
    "따라서, `Question`, `Retrieval`, `Answer` 의 3가지 정보가 필요한 것이 일반적이지만, `Retrieval` 에 대한 Ground Truth 구축이 사실상 어렵습니다.\n",
    "\n",
    "만약, `Retrieval` 에 대한 Ground Truth 가 존재한다면, 모두 데이터셋으로 저장하여 활용하고, 그렇지 않다면 `Question`, `Answer` 만으로 데이터셋을 구축하여 활용할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9fc2e8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 설치\n",
    "# !pip install -qU langsmith langchain-teddynote"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2464f16f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# API KEY를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API KEY 정보로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a6b5089",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install -qU langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH16-Evaluations\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d08b85a8",
   "metadata": {},
   "source": [
    "## 데이터셋 생성\n",
    "\n",
    "`inputs` 와 `outputs` 를 활용하여 데이터셋을 생성합니다.\n",
    "\n",
    "데이터셋은 `question` 과 `answer` 로 구성됩니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d669bc48",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# 질문과 답변 목록\n",
    "inputs = [\n",
    "    \"삼성전자가 만든 생성형 AI의 이름은 무엇인가요?\",\n",
    "    \"미국 바이든 대통령이 안전하고 신뢰할 수 있는 AI 개발과 사용을 보장하기 위한 행정명령을 발표한 날은 언제인가요?\",\n",
    "    \"코히어의 데이터 출처 탐색기에 대해서 간략히 말해주세요.\",\n",
    "]\n",
    "\n",
    "# 질문에 대한 답변 목록\n",
    "outputs = [\n",
    "    \"삼성전자가 만든 생성형 AI의 이름은 삼성 가우스 입니다.\",\n",
    "    \"2023년 10월 30일 미국 바이든 대통령이 행정명령을 발표했습니다.\",\n",
    "    \"코히어의 데이터 출처 탐색기는 AI 모델 훈련에 사용되는 데이터셋의 출처와 라이선스 상태를 추적하고 투명성을 확보하기 위한 플랫폼입니다. 12개 기관과 협력하여 2,000여 개 데이터셋의 출처 정보를 제공하며, 개발자들이 데이터의 구성과 계보를 쉽게 파악할 수 있게 돕습니다.\",\n",
    "]\n",
    "\n",
    "# 질문과 답변 쌍 생성\n",
    "qa_pairs = [{\"question\": q, \"answer\": a} for q, a in zip(inputs, outputs)]\n",
    "\n",
    "# 데이터프레임으로 변환\n",
    "df = pd.DataFrame(qa_pairs)\n",
    "\n",
    "# 데이터프레임 출력\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5c5e76e",
   "metadata": {},
   "source": [
    "혹은 이전의 튜토리얼에서 생성한 Synthetic Dataset 을 활용할 수 있습니다.\n",
    "\n",
    "아래 코드는 업로드한 HuggingFace Dataset 을 활용하는 예시입니다."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1821181",
   "metadata": {},
   "source": [
    "(참고) 아래의 주석을 풀고 실행하여 `datasets` 라이브러리를 업데이트 후 진행해 주세요. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6eb5ac03",
   "metadata": {},
   "outputs": [],
   "source": [
    "# !pip install -qU datasets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf61cb0e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from datasets import load_dataset, Dataset\n",
    "import os\n",
    "\n",
    "# huggingface Dataset에서 repo_id로 데이터셋 다운로드\n",
    "dataset = load_dataset(\n",
    "    \"teddylee777/rag-synthetic-dataset\",  # 데이터셋 이름\n",
    "    token=os.environ[\"HUGGINGFACEHUB_API_TOKEN\"],  # private 데이터인 경우 필요합니다.\n",
    ")\n",
    "\n",
    "# 데이터셋에서 split 기준으로 조회\n",
    "huggingface_df = dataset[\"korean_v1\"].to_pandas()\n",
    "huggingface_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0945775",
   "metadata": {},
   "source": [
    "## LangSmith 테스트를 위한 Dataset 생성\n",
    "\n",
    "- `Datasets & Testing` 에 새로운 데이터셋을 생성합니다.\n",
    "\n",
    "![](./assets/eval-06.png)\n",
    "\n",
    "csv 파일에서 LangSmith UI를 사용하여 직접 데이터셋을 생성할 수도 있습니다.\n",
    "\n",
    "자세한 사항은 아래 문서를 참고해 주세요.\n",
    "\n",
    "- [LangSmith UI 문서](https://docs.smith.langchain.com/evaluation/faq/manage-datasets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2566383d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langsmith import Client\n",
    "\n",
    "client = Client()\n",
    "dataset_name = \"RAG_EVAL_DATASET\"\n",
    "\n",
    "\n",
    "# 데이터셋 생성 함수\n",
    "def create_dataset(client, dataset_name, description=None):\n",
    "    for dataset in client.list_datasets():\n",
    "        if dataset.name == dataset_name:\n",
    "            return dataset\n",
    "\n",
    "    dataset = client.create_dataset(\n",
    "        dataset_name=dataset_name,\n",
    "        description=description,\n",
    "    )\n",
    "    return dataset\n",
    "\n",
    "\n",
    "# 데이터셋 생성\n",
    "dataset = create_dataset(client, dataset_name)\n",
    "\n",
    "# 생성된 데이터셋에 예제 추가\n",
    "client.create_examples(\n",
    "    inputs=[{\"question\": q} for q in df[\"question\"].tolist()],\n",
    "    outputs=[{\"answer\": a} for a in df[\"answer\"].tolist()],\n",
    "    dataset_id=dataset.id,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a46c8cc9",
   "metadata": {},
   "source": [
    "데이터셋에 예제를 나중에 추가할 수 있습니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "baf8ed6b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 새로운 질문 목록\n",
    "new_questions = [\n",
    "    \"삼성전자가 만든 생성형 AI의 이름은 무엇인가요?\",\n",
    "    \"구글이 테디노트에게 20억달러를 투자한 것이 사실입니까?\",\n",
    "]\n",
    "\n",
    "# 새로운 답변 목록\n",
    "new_answers = [\n",
    "    \"삼성전자가 만든 생성형 AI의 이름은 테디노트 입니다.\",\n",
    "    \"사실이 아닙니다. 구글은 앤스로픽에 최대 20억 달러를 투자하기로 합의했으며, 이 중 5억 달러를 우선 투자하고 향후 15억 달러를 추가로 투자하기로 했습니다.\",\n",
    "]\n",
    "\n",
    "# UI에서 업데이트된 버전 확인\n",
    "client.create_examples(\n",
    "    inputs=[{\"question\": q} for q in new_questions],\n",
    "    outputs=[{\"answer\": a} for a in new_answers],\n",
    "    dataset_id=dataset.id,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5838e50f",
   "metadata": {},
   "source": [
    "축하합니다! 이제 데이터셋이 준비되었습니다."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-kr-lwwSZlnu-py3.11",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
